import hashlib
import hmac
import sys
import configparser
from serialUtil import SerialUtil
from topic import Topic
from mainUI import *
from runTimeLogUiUtil import RunTimeLogUiUtil
from pubsubTopic import PubSubTopic
from threadUtil import ThreadUtil
ser = SerialUtil(port='COM6', bps=115200, timeout=0.5)
thread = ThreadUtil()


class Setup(Ui_Main):
    def __init__(self):
        """
        初始化
        """
        self.Main = QtWidgets.QWidget()
        self.setupUi(self.Main)
        self.init()

    def init(self):
        """
        初始化（续）
        :return:
        """
        self.tc = Topic()
        self.log = RunTimeLogUiUtil()
        self.ps = PubSubTopic()
        self.getPortList()
        self.readDeviceAll()

    def getPortList(self):
        """
        获取串口列表（按钮槽函数）
        :return:
        """
        try:
            portList = ser.getPortList()
            # portList = ['COM1', 'COM2', 'COM3']
            self.portList_CB.clear()
            self.portList_CB.addItems(['请选择串口号']+portList)
            self.log.tempFileLog(f'获取到串口列表{portList}')
            self.log.runFileLog('获取串口列表成功')
        except Exception as e:
            self.log.exceptFileLog(f'获取串口列表出错，错误原因：{e}')

    def setPort(self, port):
        """
        设置串口号（按钮槽函数）
        :param port: 串口号
        :return:
        """
        try:
            if port != '请选择串口号':
                ser.port = port
                self.log.tempFileLog(f'设置串口号为{port}')
                self.log.runFileLog(f'串口修改成功')
            else:
                self.log.runFileLog(f'串口修改失败，失败原因：选择了无效串口！')
        except Exception as e:
            self.log.exceptFileLog(f'串口修改出错，错误原因：{e}')

    def readDeviceAll(self):
        """
        读取全部设备信息（按钮槽函数）
        :return:
        """
        try:
            conf = configparser.ConfigParser()
            conf.read('./DeviceParams.ini', encoding="utf-8")
            productKey = conf.get('DeviceParams', 'productKey')
            deviceName = conf.get('DeviceParams', 'deviceName')
            deviceSecret = conf.get('DeviceParams', 'deviceSecret')
            self.productKey_LE.setText(productKey)
            self.deviceName_LE.setText(deviceName)
            self.deviceSecret_LE.setText(deviceSecret)
            self.log.tempFileLog(f'从文件./DeviceParams.ini读取到设备信息：productKey={productKey}, deviceName={deviceName}, deviceSecret={deviceSecret}')
            self.log.runFileLog(f'从文件./DeviceParams.ini读取设备信息成功')
        except Exception as e:
            self.log.exceptFileLog(f'从文件./DeviceParams.ini读取设备信息出错，错误原因：{e}')

    def writeDeviceAll(self):
        """
        写入全部设备信息（按钮槽函数）
        :return:
        """
        try:
            productKey = self.productKey_LE.text()
            deviceName = self.deviceName_LE.text()
            deviceSecret = self.deviceSecret_LE.text()
            conf = configparser.ConfigParser()
            conf.read('./DeviceParams.ini', encoding="utf-8")
            conf.set('DeviceParams', 'productKey', productKey)
            conf.set('DeviceParams', 'deviceName', deviceName)
            conf.set('DeviceParams', 'deviceSecret', deviceSecret)
            conf.write(open('./DeviceParams.ini', "w+", encoding="utf-8"))
            self.log.tempFileLog(
                f'向文件./DeviceParams.ini写入设备信息：productKey={productKey}, deviceName={deviceName}, deviceSecret={deviceSecret}')
            self.log.runFileLog(f'向文件./DeviceParams.ini写入设备信息成功')
        except Exception as e:
            self.log.exceptFileLog(f'向文件./DeviceParams.ini写入设备信息出错，错误原因：{e}')

    def connect(self):
        """
        连接设备（按钮槽函数）
        :return:
        """
        try:
            conf = configparser.ConfigParser()
            conf.read('./DeviceParams.ini', encoding="utf-8")
            productKey = conf.get('DeviceParams', 'productKey')
            deviceName = conf.get('DeviceParams', 'deviceName')
            deviceSecret = conf.get('DeviceParams', 'deviceSecret')
            self.log.tempFileLog(
                f'从文件./DeviceParams.ini读取到设备信息：productKey={productKey}, deviceName={deviceName}, deviceSecret={deviceSecret}')
            data = {
            "ProductKey": productKey,
            "DeviceName": deviceName,
            "DeviceSecret": deviceSecret
            }
            clientId, username, password = self.hmacsha1(data)
            usernameResult = ser.PubSub(data=f'AT+PRODUCTKEY={username}')
            self.log.tempFileLog(f'发布：AT+PRODUCTKEY={username}并订阅：{usernameResult}')
            passwordResult = ser.PubSub(data=f'AT+PASSWORD={password}')
            self.log.tempFileLog(f'发布：AT+PASSWORD={password}并订阅：{passwordResult}')
            clientIdResult = ser.PubSub(data=f'AT+CLINETID={clientId}')
            self.log.tempFileLog(f'发布：AT+CLINETID={clientId}并订阅：{clientIdResult}')
            conncectResult = ser.PubSub(data='AT+CONNECT')
            self.log.tempFileLog(f'发布：AT+CONNECT并订阅：{conncectResult}')

            self.tc.ser = ser
            self.tc.rstCallback = self.rst
            self.tc.log = self.log
            self.tc.init()
            self.tc.Form.show()
            self.Main.close()

            self.ps.ser = ser
            self.ps.log = self.log
            thread.startThread(self.ps.main)

            self.log.runFileLog(f'设备连接成功')
        except Exception as e:
            self.log.exceptFileLog(f'设备连接出错，错误原因：{e}')

    def rst(self):
        """
        设备复位（按钮槽函数）
        :return:
        """
        try:
            rstResult = ser.PubSub(data='AT+RST')
            self.log.tempFileLog(f'发布：AT+RST并订阅：{rstResult}')
            self.tc.Form.close()
            self.Main.show()
            thread.stopThread()
            self.log.runFileLog(f'设备复位成功')
        except Exception as e:
            self.log.exceptFileLog(f'设备复位出错，错误原因：{e}')

    def hmacsha1(self, data):
        """
        hmacsha1阿里设备三元组数据解析
        :param data: 设备三元组
        :return: clientId, username, password
        """
        ProductKey = data['ProductKey']
        DeviceName = data['DeviceName']
        DeviceSecret = data['DeviceSecret']

        clientId = "".join((DeviceName,
                             "|securemode=3",
                             ",signmethod=", "hmacsha1"
                             "|"))

        username = "".join((DeviceName, "&", ProductKey))
        data = "".join(("clientId", DeviceName, "deviceName", DeviceName,
                        "productKey", ProductKey))
        password = hmac.new(bytes(DeviceSecret.encode('utf8')), bytes(data.encode('utf8')), hashlib.sha1).hexdigest().upper()

        return clientId, username, password

    def readProductKey(self):
        """
        读取productKey（按钮槽函数）
        :return:
        """
        try:
            conf = configparser.ConfigParser()
            conf.read('./DeviceParams.ini', encoding="utf-8")
            productKey = conf.get('DeviceParams', 'productKey')
            self.log.tempFileLog(
                f'从文件./DeviceParams.ini读取到productKey={productKey}')
            self.productKey_LE.setText(productKey)
            self.log.runFileLog(f'重置productKey成功')
        except Exception as e:
            self.log.exceptFileLog(f'重置productKey出错，错误原因：{e}')

    def writeProductKey(self):
        """
        写入productKey（按钮槽函数）
        :return:
        """
        try:
            productKey = self.productKey_LE.text()
            print(productKey)
            conf = configparser.ConfigParser()
            conf.read('./DeviceParams.ini', encoding="utf-8")
            conf.set('DeviceParams', 'productKey', productKey)
            conf.write(open('./DeviceParams.ini', "w+", encoding="utf-8"))
            self.log.tempFileLog(
                f'向文件./DeviceParams.ini写入productKey={productKey}')
            self.log.runFileLog(f'更新productKey成功')
        except Exception as e:
            self.log.exceptFileLog(f'更新productKey出错，错误原因：{e}')

    def readDeviceSecret(self):
        """
        读取deviceSecret（按钮槽函数）
        :return:
        """
        try:
            conf = configparser.ConfigParser()
            conf.read('./DeviceParams.ini', encoding="utf-8")
            deviceSecret = conf.get('DeviceParams', 'deviceSecret')
            self.log.tempFileLog(
                f'从文件./DeviceParams.ini读取到deviceSecret={deviceSecret}')
            self.deviceSecret_LE.setText(deviceSecret)
            self.log.runFileLog(f'重置deviceSecret成功')
        except Exception as e:
            self.log.exceptFileLog(f'重置deviceSecret出错，错误原因：{e}')

    def writeDeviceSecret(self):
        """
        写入deviceSecret（按钮槽函数）
        :return:
        """
        try:
            deviceSecret = self.deviceSecret_LE.text()
            conf = configparser.ConfigParser()
            conf.read('./DeviceParams.ini', encoding="utf-8")
            conf.set('DeviceParams', 'deviceSecret', deviceSecret)
            conf.write(open('./DeviceParams.ini', "w+", encoding="utf-8"))
            self.log.tempFileLog(
                f'向文件./DeviceParams.ini写入deviceSecret={deviceSecret}')
            self.log.runFileLog(f'更新deviceSecret成功')
        except Exception as e:
            self.log.exceptFileLog(f'更新deviceSecret出错，错误原因：{e}')

    def readDeviceName(self):
        """
        读取deviceName（按钮槽函数）
        :return:
        """
        try:
            conf = configparser.ConfigParser()
            conf.read('./DeviceParams.ini', encoding="utf-8")
            deviceName = conf.get('DeviceParams', 'deviceName')
            self.log.tempFileLog(
                f'从文件./DeviceParams.ini读取到deviceName={deviceName}')
            self.deviceName_LE.setText(deviceName)
            self.log.runFileLog(f'重置deviceName成功')
        except Exception as e:
            self.log.exceptFileLog(f'重置deviceName出错，错误原因：{e}')

    def writeDeviceName(self):
        """
        写入deviceName（按钮槽函数）
        :return:
        """
        try:
            deviceName = self.deviceName_LE.text()
            conf = configparser.ConfigParser()
            conf.read('./DeviceParams.ini', encoding="utf-8")
            conf.set('DeviceParams', 'deviceName', deviceName)
            conf.write(open('./DeviceParams.ini', "w+", encoding="utf-8"))
            self.log.tempFileLog(
                f'向文件./DeviceParams.ini写入deviceName={deviceName}')
            self.log.runFileLog(f'更新deviceName成功')
        except Exception as e:
            self.log.exceptFileLog(f'更新deviceName出错，错误原因：{e}')


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    setup = Setup()
    setup.Main.show()
    sys.exit(app.exec_())